package com.demo.test.leak;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;

import androidx.annotation.Nullable;

import com.base.tool.log.LogPrint;
import com.demo.Tags;
import com.fortest.R;

/**
 泄露方式：非静态内部类默认持有外部类的引用——handler
 泄露原因： Handler　postDelayed了一个很久才执行的任务到主线程的消息队列去排队等待执行，
 这个任务是个“匿名内部类”，是Runnable的子类，是非静态内部类（包括匿名内部类），默认持有外部类（Activity）的引用，
 显然主线程的生命周期比Activity长，
 当Activity退出时，若任务还没执行完，消息队列中的消息持有Runnable对象引用，Runnable对象持有Activity，导致Activity泄露。

 泄露报告　－－　StrictMode：
 2020-05-24 17:51:46.689 3221-3221/com.example.myapplication E/StrictMode: class com.demo.test.leak.ActivityLeakA_Handler; instances=2; limit=1
 android.os.StrictMode$InstanceCountViolation: class com.demo.test.leak.ActivityLeakA_Handler; instances=2; limit=1
 at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

 泄露报告　－－　LeakCanary：
 33136 bytes retained by leaking objects
 Signature: bc1a1dd8c8cc83029d21a77fb692b1cef3ed765
 ┬───
 │ GC Root: Input or output parameters in native code
 │
 ├─ android.os.MessageQueue instance
 │    Leaking: NO (MessageQueue#mQuitting is false)
 │    ↓ MessageQueue.mMessages
 │                   ~~~~~~~~~
 ├─ android.os.Message instance
 │    Leaking: UNKNOWN
 │    ↓ Message.callback
 │              ~~~~~~~~
 ├─ com.demo.test.leak.ActivityLeakA_Handler$1 instance
 │    Leaking: UNKNOWN
 │    Anonymous class implementing java.lang.Runnable
 │    ↓ ActivityLeakA_Handler$1.this$0
 │                              ~~~~~~
 ╰→ com.demo.test.leak.ActivityLeakA_Handler instance
 ​     Leaking: YES (ObjectWatcher was watching this because com.demo.test.leak.ActivityLeakA_Handler received Activity#onDestroy() callback and Activity#mDestroyed is true)
 ​     key = 8f410d28-c61f-49b8-8965-48cc46b5a78f
 ​     watchDurationMillis = 6787
 ​     retainedDurationMillis = 1782

 **/
public class ActivityLeakA_Handler extends Activity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak_common);
        TextView textView = findViewById(R.id.helper_text);
        textView.setText(" 泄露方式：非静态内部类默认持有外部类的引用——handler\n" +
                " 泄露原因： Handler　postDelayed了一个很久才执行的任务到主线程的消息队列去排队等待执行，\n" +
                " 这个任务是个“匿名内部类”，是Runnable的子类，是非静态内部类（包括匿名内部类），默认持有外部类（Activity）的引用，\n" +
                " 显然主线程的生命周期比Activity长，\n" +
                " 当Activity退出时，若任务还没执行完，消息队列中的消息持有Runnable对象引用，Runnable对象持有Activity，导致Activity泄露。\n");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {

            }
        }, 1000000);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        LogPrint.e(Tags.gc, this.getLocalClassName() + "  finalize");
    }
}